package pl.jtb.ctl.tabory.dao.impl.mybatis.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.log4j.Logger;

import pl.jtb.ctl.tabory.dao.api.services.ICompositionService;
import pl.jtb.ctl.tabory.dao.api.services.IVagonService;
import pl.jtb.ctl.tabory.dao.data.vo.CompositionVO;
import pl.jtb.ctl.tabory.dao.data.vo.VagonVO;
import pl.jtb.ctl.tabory.dao.impl.mybatis.base.BaseDaoService;
import pl.jtb.ctl.tabory.dao.impl.mybatis.servicemanager.ServiceManager;

public class CompositionServiceImpl extends BaseDaoService<CompositionVO> implements ICompositionService {

    private final static Logger logger = Logger.getLogger(CompositionServiceImpl.class);

    private final static String MAPPER = "pl.jtb.ctl.taboty.CompositionMapper";
    private final static String SQL_SELECT_ALL_COMPOSITIONS = ".selectAllCompositions";
    private final static String SQL_SAVE_COMPOSITION = ".saveComposition";
    private final static String SQL_UPDATE_COMPOSITION = ".updateComposition";
    private final static String SQL_SELECT_COMPOSITION_BY_ID = ".selectCompositionById";
    private final static String SQL_SELECT_COMPOSITION_BY_INTERNAL_ID = ".selectCompositionByInternalId";
    private final static String SQL_DELETE_COMPOSITION = ".deleteComposition";
    private final static String SQL_SAVE_COMPOSITION_VALUE = ".saveCompositionValue";
    private final static String SQL_DELETE_COMPOSITION_VALUES_FOR_COMPOSITION = ".deleteCompositionValuesForComposition";
    private final static String SQL_SELECT_COMPOSITION_VALUES_FOR_COMPOSITION = ".selectCompositionValuesForComposition";

    public CompositionServiceImpl(SqlSessionFactory sqlSessionFactory) {
        super(sqlSessionFactory);
    }

    @Override
    public List<CompositionVO> getListAllCompositions() throws Exception {
        logger.debug("Getting all Compositions");
        List<CompositionVO> result = null;
        try {
            result = selectList(MAPPER + SQL_SELECT_ALL_COMPOSITIONS, null);
        } catch (Exception e) {
            result = new ArrayList<CompositionVO>();
            logger.error(e.getMessage(), e);
            throw e;
        }
        return result;
    }

    @Override
    public CompositionVO getComposition(final String internalId) throws Exception {
        logger.debug("Getting Composition by InternalId: " + internalId);
        CompositionVO result = null;
        try {
            result = selectOne(MAPPER + SQL_SELECT_COMPOSITION_BY_INTERNAL_ID, internalId);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw e;
        }
        return result;
    }

    @Override
    public CompositionVO getComposition(final Long id) throws Exception {
        logger.debug("Getting Composition by ID: " + id);
        CompositionVO result = null;
        try {
            result = selectOne(MAPPER + SQL_SELECT_COMPOSITION_BY_ID, id);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw e;
        }
        return result;
    }

    @Override
    public CompositionVO saveUpdateComposition(final CompositionVO composition) throws Exception {
        logger.debug("Save/Update Compostion: " + composition);
        composition.setActive(true);
        if (composition.getId() == null) {
            saveComposition(composition);
        } else {
            updateComposition(composition);
        }
        return composition;
    }

    private void saveComposition(final CompositionVO composition) throws Exception {
        logger.debug("Saving new Composition");
        try {
            create(MAPPER + SQL_SAVE_COMPOSITION, composition);
        } catch (Exception e) {
            composition.setId(null);
            logger.error(e.getMessage(), e);
            throw e;
        }
    }

    private void updateComposition(final CompositionVO composition) throws Exception {
        logger.debug("Updating existing Composition");
        try {
            update(MAPPER + SQL_UPDATE_COMPOSITION, composition);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw e;
        }
    }

    @Override
    public void deleteComposition(CompositionVO composition) throws Exception {
        logger.debug("Deleting Composition: " + composition);
        try {
            delete(MAPPER + SQL_DELETE_COMPOSITION, composition);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw e;
        }
    }

    @Override
    public Map<CompositionVO, List<VagonVO>> saveUpdateCompositionVagonRelation(Map<CompositionVO, List<VagonVO>> relation) throws Exception {
        logger.debug("Saving composition to vagon relation for: " + relation.keySet());
        try {
            for (Entry<CompositionVO, List<VagonVO>> entry : relation.entrySet()) {
                CompositionVO composition = entry.getKey();
                List<VagonVO> value = entry.getValue();
                if (value == null) {
                    continue;
                }
                deleteCompositionValues(composition);
                for (VagonVO vagonVO : value) {
                    Map<String, Object> map = new HashMap<String, Object>();
                    map.put("compositionId", composition.getId());
                    map.put("vagonId", vagonVO.getId());
                    create(MAPPER + SQL_SAVE_COMPOSITION_VALUE, map);
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw e;
        }
        return relation;
    }

    @SuppressWarnings("unchecked")
    @Override
    public Map<CompositionVO, List<VagonVO>> getCompositionVagonRelation(CompositionVO composition) throws Exception {
        Map<CompositionVO, List<VagonVO>> result = new HashMap<CompositionVO, List<VagonVO>>();
        logger.debug("Getting composition values for composition: " + composition);
        SqlSession session = sessionFactory.openSession();
        try {
            List<Long> list = session.selectList(MAPPER + SQL_SELECT_COMPOSITION_VALUES_FOR_COMPOSITION, composition.getId());
            if (list != null) {
                IVagonService vagonService = ServiceManager.getInstance().getVagonService();
                List<VagonVO> vagons = vagonService.getVagons(list);
                result.put(composition, vagons);
            }
            session.commit();
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw e;
        } finally {
            session.close();
        }
        return result;
    }

    @Override
    public void deleteCompositionValues(CompositionVO composition) throws Exception {
        logger.debug("Deleting composition values for composition: " + composition);
        try {
            delete(MAPPER + SQL_DELETE_COMPOSITION_VALUES_FOR_COMPOSITION, composition.getId());
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw e;
        }

    }

}
